package readHandle

import (
	"chart.zozoo.net/app/dao/messageDao"
	"chart.zozoo.net/app/dao/messageHistoryDao"
	"chart.zozoo.net/app/models"
	"chart.zozoo.net/app/service/userService"
	"chart.zozoo.net/app/service/usersOnlineService"
	"chart.zozoo.net/app/socket/connManage"
	"chart.zozoo.net/app/socket/writeHandle"
	"chart.zozoo.net/app/utils/arrayUtils"
	"chart.zozoo.net/app/utils/commonFunc"
	"chart.zozoo.net/core/conf"
	"chart.zozoo.net/core/myRedis"
	"encoding/json"
	"errors"
	"fmt"
	"time"
)

var limitMsgType = []string{
	"text",
	"image",
	"video",
	"audio",
}

// 处理聊天消息
func handleChatMsg(msg string, addr string) {
	chatMsg := &ChatMessage{}
	err := json.Unmarshal([]byte(msg), chatMsg)
	if err != nil {
		fmt.Println(err)
		return
	}

	//验证消息类型
	au := new(arrayUtils.ArrayUtils)
	if !au.Contains(limitMsgType, chatMsg.MsgType) {
		//消息类型不允许
		return
	}

	//获取接收用户信息
	toUser, err := userService.InfoByUuid(chatMsg.ToUid)
	if err != nil {
		fmt.Println(err)
		return
	}

	//发送用户信息
	fromUser := connManage.GetConn(addr).UserInfo

	/**
	  	记录消息内容 message
	  	记录写入聊天记录 message_history
	  	写入聊天列表缓存-hash
		对方如果在线，推送消息给对方
	*/

	message := &models.Message{
		MsgId:      commonFunc.GenerateMsgId(fromUser.Id, toUser.Id),
		FromUid:    fromUser.Uuid,
		ToUid:      toUser.Uuid,
		MsgType:    chatMsg.MsgType,
		MsgContent: chatMsg.MsgContent,
		CreatedAt:  time.Now(),
	}
	if err = messageDao.Create(message); err != nil {
		fmt.Println(err)
		return
	}

	//设置聊天记录
	err = setHistory(fromUser, toUser, message)
	if err != nil {
		fmt.Println("设置聊天记录失败", err)
		return
	}

	//发送消息
	err = sendMsg(toUser, message)
	if err != nil {
		fmt.Println(err)
		return
	}
}

// 设置聊天记录
func setHistory(fromUser, toUser *models.Users, msg *models.Message) (err error) {
	//设置我的聊天记录

	err = setHistoryByUser(fromUser, toUser.Uuid, msg, 0)
	if err != nil {
		return
	}
	//设置用户的聊天记录
	err = setHistoryByUser(toUser, fromUser.Uuid, msg, 1)
	if err != nil {
		return
	}
	return
}

// 设置用户聊天记录
func setHistoryByUser(user *models.Users, fUuid string, msg *models.Message, unreadNum int) (err error) {
	//记录缓存
	myHashKey := GetMessageHistoryCacheKey(user.Id)
	cmd := myRedis.RedisClient.HGet(myHashKey, fUuid)
	history := new(models.MessageHistory)
	if cmd.Err() == nil {
		//存在缓存，将缓存转换为对象，再修改对象，再保存缓存
		err = json.Unmarshal([]byte(cmd.Val()), history)
		if err != nil {
			return err
		}
		history.MsgView = getMsgViewVal(msg)

		//定义未读消息数量
		history.UnreadNum = history.UnreadNum + unreadNum
		if unreadNum == 0 {
			history.UnreadNum = 0
		}
		history.CreatedAt = time.Now()
		//保存数据库
		if err = messageHistoryDao.UpdateById(
			history.Id,
			map[string]interface{}{
				"unread_num": history.UnreadNum,
				"msg_view":   history.MsgView,
				"created_at": history.CreatedAt,
			},
		); err != nil {
			return errors.New(fmt.Sprintf("修改聊天历史失败，err:%v", err))
		}
	} else {
		//缓存不存在，查询数据库
		if history, err = messageHistoryDao.GetByUuid(user.Id, fUuid); err != nil {
			return errors.New(fmt.Sprintf("获取聊天历史失败，err:%v", err))
		}

		if history.Id == 0 {
			//不存在数据,创建
			history.MsgView = getMsgViewVal(msg)
			history.UnreadNum = unreadNum
			history.Uid = user.Id
			history.FUuid = fUuid
			if err = messageHistoryDao.Create(history); err != nil {
				return errors.New(fmt.Sprintf("创建聊天历史失败，err:%v", err))
			}
		} else {
			//存在数据,修改
			history.MsgView = getMsgViewVal(msg)
			history.UnreadNum = history.UnreadNum + unreadNum
			if unreadNum == 0 {
				history.UnreadNum = 0
			}
			history.CreatedAt = time.Now()

			if err = messageHistoryDao.UpdateById(history.Id, map[string]interface{}{
				"unread_num": history.UnreadNum,
				"msg_view":   history.MsgView,
				"created_at": history.CreatedAt,
			}); err != nil {
				return errors.New(fmt.Sprintf("修改聊天历史失败，err:%v", err))
			}
		}
	}

	//保存缓存
	str, err := json.Marshal(history)
	if err != nil {
		return errors.New(fmt.Sprintf("history转json失败，err:%v", err))
	}
	return myRedis.RedisClient.HSet(myHashKey, fUuid, string(str)).Err()
}

// 获取消息预览内容
func getMsgViewVal(msg *models.Message) string {
	if msg.MsgType == "text" {
		arr := []rune(msg.MsgContent)
		if len(arr) < 10 {
			return msg.MsgContent
		}

		return string(arr[0:10])
	}

	switch msg.MsgType {
	case "image":
		return "[图片]"
	case "video":
		return "[视频]"
	case "audio":
		return "[音频]"
	default:
		return ""
	}
}

// 发送消息
func sendMsg(user *models.Users, msg *models.Message) (err error) {
	//获取用户在线状态
	online, err := usersOnlineService.Info(user.Uuid)
	if err != nil {
		return
	}

	//用户如果不在线，结束执行
	if online.Status == 0 {
		return
	}

	//获取用户所在的服务器是否是当前服务器，
	//是当前服务器时直接获取当前的socket连接发送消息
	//是其他服务器时，将消息推送到rabbitMq服务器发送消息
	if online.Host == conf.Conf.Server.Host {

		//判断当前是否在线
		connInfo := connManage.GetConn(online.Addr)
		if connInfo == nil {
			//当前不在线,修改在线状态
			return usersOnlineService.Update(user.Uuid, 0, "")
		}

		str, err := json.Marshal(msg)
		if err != nil {
			return err
		}

		chatMsg := ChatMessage{
			ToUid:      user.Uuid,
			MsgType:    "chatMsg",
			MsgContent: string(str),
		}

		writeHandle.WriteMessage(connInfo.Conn, chatMsg)
		return err
	}

	return err
}
